/****************************************************************
 * Fulguro
 * Copyright (C) 2004 Christophe Clienti
 *
 * This library is free software; you can redistribute it and/or
 * modify it under the terms of the GNU Lesser General Public
 * License as published by the Free Software Foundation; either
 * version 2 of the License, or (at your option) any later version.
 *
 * This library is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
 * Lesser General Public License for more details.
 *
 * You should have received a copy of the GNU Lesser General Public
 * License along with this library; if not, write to the
 * Free Software Foundation, Inc., 59 Temple Place - Suite 330,
 * Boston, MA 02111-1307, USA.
 ***************************************************************/

#include <stdarg.h>
#include <SDL/SDL_thread.h>

#include "flgrCoreMalloc.h"
#include "flgrCoreThreads.h"


  /*!
   * \defgroup group_fulguro_core_thread Threads
   * \ingroup group_fulguro_core
   * @{
   */



////////////////////////////////////////////////////////////////////////////
/*! Create and allocate the threads arguments list
 *  @param threads_nb : total number of threads
 *  @returns FLGR_ThreadsArgList pointer
 */
//////////////////////////////////////////////////////////////////
FLGR_ThreadsArgList* flgr_threads_create_argument_list(int threads_nb) {
  FLGR_ThreadsArgList *arglist;
  int i;
 
  arglist = (FLGR_ThreadsArgList*) flgr_malloc(sizeof(FLGR_ThreadsArgList));

  arglist->threads_nb  = threads_nb;
  arglist->threads_arg = (FLGR_ThreadsArg **) flgr_malloc(threads_nb * sizeof(FLGR_ThreadsArg*));


  for(i=0 ; i<threads_nb ; i++) {
    arglist->threads_arg[i] = (FLGR_ThreadsArg *) flgr_malloc(sizeof(FLGR_ThreadsArg));
  }

  return arglist;
}



////////////////////////////////////////////////////////////////////////////
/*! Store argument of a thread into the threads arguments list
 *  @param arglist : FLGR_ThreadsArgList pointer
 *  @param thread_index : which thread to store arguments
 *  @returns nothings
 */
//////////////////////////////////////////////////////////////////
void flgr_threads_set_argument(FLGR_ThreadsArgList* arglist, int thread_index, ...) {
  FLGR_ThreadsArg *parg = arglist->threads_arg[thread_index];
  va_list s;
  int j;

  va_start(s, thread_index);

  parg->argc = va_arg(s, int);
  
  parg->argv = (void **) flgr_malloc( parg->argc * sizeof(void*) );
    
  for(j=0 ; j<parg->argc ; j++) {
    parg->argv[j] = va_arg(s, void*);
  }

  va_end(s);

}




////////////////////////////////////////////////////////////////////////////
/*! destroy the threads arguments list. Threads Argument pointer to user data
 *  must be freed before.
 *  @param arglist : FLGR_ThreadsArgList pointer
 *  @returns nothings
 */
//////////////////////////////////////////////////////////////////
void flgr_threads_destroy_argument_list(FLGR_ThreadsArgList *arglist) {
  int i;
  
  if(arglist==NULL) return;

  for(i=0 ; i<arglist->threads_nb ; i++) {
    flgr_free(arglist->threads_arg[i]->argv);
    flgr_free(arglist->threads_arg[i]);
  }

  flgr_free(arglist->threads_arg);

  flgr_free(arglist);
}







////////////////////////////////////////////////////////////////////////////
/*! Start threads
 *  @param arglist : FLGR_ThreadsArgList pointer
 *  @param threads_nb_per_fct : number of thread per function
 *  @param threads_fct_nb : number of different functions to use as thread
 *  @returns FLGR_RET_OK, ...
 */
//////////////////////////////////////////////////////////////////
FLGR_Ret flgr_threads_start(FLGR_ThreadsArgList *arglist, 
			    int threads_nb_per_fct, int threads_fct_nb, ...) {

  FLGR_ThreadFunction *fct_array;
  SDL_Thread **threads;
  va_list s;
  int th_nb;
  int i,j,k=0;

  th_nb = threads_fct_nb * threads_nb_per_fct;

  if(arglist->threads_nb != th_nb) {
    POST_ERROR("Threads numbers specified in arglist does not match to number of thread given here!");
    return FLGR_RET_PARAM_ERROR;
  }

  fct_array = (FLGR_ThreadFunction *) flgr_malloc(threads_fct_nb * sizeof(FLGR_ThreadFunction));
  threads   = (SDL_Thread **) flgr_malloc(th_nb * sizeof(SDL_Thread*));


  va_start(s, threads_fct_nb);
 
  for(i=0 ; i<threads_fct_nb ; i++) {
    fct_array[i] = va_arg(s, FLGR_ThreadFunction);
  }

  va_end(s);


  //launch threads
  for(i=0,k=0 ; i< threads_fct_nb ; i++) {
    for(j=0 ; j<threads_nb_per_fct ; j++,k++) {
      threads[k] = SDL_CreateThread(fct_array[i], arglist->threads_arg[k]);
    }
  }

  //wait end of threads
  for(i=0 ; i<th_nb ; i++) {
    SDL_WaitThread(threads[i], NULL);
  }
  

  flgr_free(fct_array);
  flgr_free(threads);

  return FLGR_RET_OK;
}




